package com.ogawa.a7517.mqtt;

import android.content.Context;
import android.util.Log;

import com.google.gson.Gson;
import com.ogawa.a7517.Constant;
import com.ogawa.a7517.bean.DeviceOffBean;
import com.ogawa.a7517.bean.DeviceStateBean;
import com.ogawa.a7517.bean.MassageArmchair;
import com.ogawa.a7517.bean.PublishBean;

import org.eclipse.paho.android.service.MqttAndroidClient;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

public class MqttManager implements MqttCallbackExtended {
    private MqttAndroidClient mqttClient;
    private MqttConnectOptions options;
    private ScheduledExecutorService pool = Executors.newScheduledThreadPool(5);
    private String clientId;
    private MqttConnectListener mConnectListener;
    private List<MqttDeviceStateListener> mDeviceStateListeners = new ArrayList<>();
    private List<MqttSendMsgCallback> mMsgSendCallbacks = new ArrayList<>();
    private Gson mGson;
    private Context mContext;

    private MqttManager() {

    }

    public static MqttManager getInstance() {
        return InstanceHolder.INSTANCE;
    }

    /**
     * 初始化MqttClient
     *
     * @param context
     */
    public void initClient(Context context) {
        clientId = "android" + (int) ((Math.random() * 9 + 1) * 10000);
        mContext = context.getApplicationContext();
        mqttClient = new MqttAndroidClient(mContext, Constant.HOST, clientId);
        mqttClient.setCallback(this);
        options = new MqttConnectOptions();
        options.setCleanSession(true);
        options.setAutomaticReconnect(true);
        options.setConnectionTimeout(500);
        options.setKeepAliveInterval(20);
        options.setMaxReconnectDelay(3000);
        options.setMaxInflight(10);
        mGson = new Gson();
    }

    public String getClientId() {
        return clientId;
    }

    public void setMqttConnectListener(MqttConnectListener listener) {
        mConnectListener = listener;
    }

    public void clearMqttConnectListener() {
        mConnectListener = null;
    }

    public void registerMqttSendMsgCallback(MqttSendMsgCallback callback) {
        if (!mMsgSendCallbacks.contains(callback)) {
            mMsgSendCallbacks.add(callback);
        }
    }

    public void unRegisterMqttSendMsgCallback(MqttSendMsgCallback callback) {
        mMsgSendCallbacks.remove(callback);
    }

    public void registerMqttDeviceStateListener(MqttDeviceStateListener listener) {
        if (!mDeviceStateListeners.contains(listener)) {
            mDeviceStateListeners.add(listener);
        }
    }

    public void unRegisterMqttDeviceStateListener(MqttDeviceStateListener listener) {
        mDeviceStateListeners.remove(listener);
    }

    /**
     * 建立Mqtt连接
     *
     * @param userName
     * @param psw
     */
    public void connect(String userName, String psw) {
        options.setUserName(userName);
        options.setPassword(psw.toCharArray());
        pool.execute(() -> {
            try {
                mqttClient.connect(options);
            } catch (MqttException e) {
                e.printStackTrace();
            }
        });
    }

    /**
     * 订阅主题
     */
    public void subscribe(String[] topics, int[] qos, IMqttActionListener listener) {
        try {
            mqttClient.subscribe(topics, qos, mContext, listener);
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

    private void publish(String topic, int qos, String content) {
        if (!isConnect()) {
            return;
        }
        MqttMessage message = new MqttMessage(content.getBytes());
        message.setQos(qos);
        pool.execute(() -> {
            try {
                mqttClient.publish(topic, message);
            } catch (MqttException e) {
                e.printStackTrace();
            }
        });
    }

    /**
     * 发布消息,带附加值
     *
     * @param func
     * @param model
     */
    public void publish(String func, String model, String addition) {
        PublishBean bean = new PublishBean();
        bean.setFunctionCode(func);
        bean.setModelValue(model);
        bean.setClientId(clientId);
        bean.setAdditionalValue(addition);
        publish("cmd/down/" + bean.getSn(), 2, mGson.toJson(bean));
    }

    /**
     * 发布消息，不带附加值
     *
     * @param func
     * @param model
     */
    public void publish(String func, String model) {
        publish(func, model, null);
    }

    /**
     * 是否连接
     *
     * @return
     */
    public boolean isConnect() {
        return mqttClient.isConnected();
    }

    /**
     * 断开连接
     */
    public void disconnect() {
        if (isConnect()) {
            try {
                mqttClient.disconnect();
                onConnectChange(false);
            } catch (MqttException e) {
                e.printStackTrace();
            }
        }
    }

    private void onConnectChange(boolean connect) {
        if (mConnectListener != null) {
            mConnectListener.onConnectStateChange(connect);
        }
    }

    /**
     * 连接丢失
     *
     * @param cause
     */
    @Override
    public void connectionLost(Throwable cause) {
        onConnectChange(false);
    }

    /**
     * 收到信息
     *
     * @param topic
     * @param message
     * @throws Exception
     */
    @Override
    public void messageArrived(String topic, MqttMessage message) throws Exception {
        String msg = new String(message.getPayload());
//        Log.e("tag", topic + "-----------messageArrived---------" + msg);
        if (topic.contains("up")) {//设备状态的消息
            if (!msg.contains("fault") && !msg.contains("elecTime") && !msg.contains("heartbeat")) {
                DeviceStateBean deviceStatusBean = mGson.fromJson(msg, DeviceStateBean.class);
                DeviceStateBean.FunctionsBean.RunningStatusBean runningStatus =
                        deviceStatusBean.getFunctions().getRunningStatus();
                if (runningStatus != null) {
                    int state = Integer.parseInt(runningStatus.getModelValue());
                    MassageArmchair.getInstance().setRunningStatus(state);
                    if (state == 0) {
                        MassageArmchair.getInstance().setDeviceStatusBean(null);
                    }
                }
                DeviceStateBean.FunctionsBean.ResetSucccessFlag resetSucccessFlag
                        = deviceStatusBean.getFunctions().getResetSucccessFlag();
                if (resetSucccessFlag != null) {//复位标志即为关机信号
                    MassageArmchair.getInstance().setRunningStatus(0);
                    DeviceOffBean deviceOffBean = mGson.fromJson(msg, DeviceOffBean.class);
                    MassageArmchair.getInstance().setDeviceStatusBean(null);
                    MassageArmchair.getInstance().setDeviceOffBean(deviceOffBean);
                }
                if (deviceStatusBean.getFunctions().getAutoProgram() != null) {
                    MassageArmchair.getInstance().setDeviceStatusBean(deviceStatusBean);
                    MassageArmchair.getInstance().setDeviceOffBean(null);
                }
            } else if (msg.contains("fault")) {
                String functions = new JSONObject(msg).getString("functions");
                String fault = new JSONObject(functions).getString("fault");
                String faultResult = new JSONObject(fault).getString("modelValue");
                MassageArmchair.getInstance().setFault(faultResult);
            }
            for (MqttDeviceStateListener mDeviceStateListener : mDeviceStateListeners) {
                mDeviceStateListener.onDeviceStateChange();
            }
        } else if (topic.contains("back")) {//发送消息的回复
            String cmdResult = new JSONObject(msg).getString("cmdResult");
            int sendState = 0;
            switch (cmdResult) {
                case "success":
                    sendState = MqttSendMsgCallback.SUCCESS;
                    break;
                case "fail":
                    sendState = MqttSendMsgCallback.FAIL;
                    break;
                case "timeout":
                    sendState = MqttSendMsgCallback.TIMEOUT;
                    break;
                case "offline":
                    sendState = MqttSendMsgCallback.OFFLINE;
                    break;
            }
            for (MqttSendMsgCallback mMsgSendCallback : mMsgSendCallbacks) {
                mMsgSendCallback.sendMsgCallback(sendState);
            }
        }
    }

    @Override
    public void deliveryComplete(IMqttDeliveryToken token) {

    }

    /**
     * 建立连接成功
     *
     * @param reconnect
     * @param serverURI
     */
    @Override
    public void connectComplete(boolean reconnect, String serverURI) {
        onConnectChange(true);
    }

    private static class InstanceHolder {
        private static final MqttManager INSTANCE = new MqttManager();
    }
}
